Modem database servers provide facilities for organizing activities of application programs that use the database servers into logical transactions. Generally, when an application program initiates a particular transaction, it cannot carry out database operations outside the transaction until the transaction commits and completes, unless the application program logically separates the current transaction and establishes a new transaction. In the past, such logical separation has required the use of explicit programming language statements such as "detach" and "attach." These statements require the programmer, as the program is being written, to keep track of which transaction is current.
In some situations during the execution of a particular transaction, it is necessary to be able to carry out one or more operations that are outside the scope of the particular transaction. For example, consider a transaction having a long duration that periodically stores debugging information in a database table. Normally, storage actions of a transaction, such as changes to database tables, are not "committed" or made permanent if the transaction aborts or fails abnormally. However, in this example, it is important for the operations that involve storage of information in the debug table to be committed even, or especially, when the transaction aborts. In other words, the debug table storage operations should be carried out in an independent or "autonomous" transaction.
As another example, in certain financial applications, such as an accounting application, it is useful to have a mechanism to create, store, and commit account code information without giving consideration to the outcome of the transaction that is the source of a need to create an account code. Consider another example involving an application having transactions that call an audit log transaction that creates an audit log file. It is desirable to retain the audit log file even if the calling transaction fails, because the audit information might be useful in showing what went wrong.
In one past approach, an autonomous transaction is managed using transaction commands for attaching and detaching transactions. This approach is used, for example, in the Oracle C Interface (OCI) for the Oracle8.RTM. database system. As an example, if the long-duration transaction described in the above example is named "trans 1," the following program code could provide transaction independence:
execute trans1 detach attach (trans2) {execute some statements that store debug information} commit /* commits changes made to the debug table */ attach (trans 1) {resume execution of trans1} commit /* commits changes made by trans1 */
However, this approach suffers from several drawbacks, including the following. First, the approach is error-prone, since the programmer must, after each "detach" command, specify the correct transaction to be attached. This requirement can cause errors in situations involving long, nested sequences of independent transactions. For example, the requirement of matching transaction names is unwieldy in code in which one transaction calls another transaction that calls yet another transaction.
Second, in the above approach, certain deadlock situations may become impossible to detect. For example, if in the above example the transaction trans1 holds a particular resource (e.g., a table lock) that is required by trans2, a deadlock situation would occur. A deadlock arises because transI cannot complete and release the resource until trans2 completes, which can't complete until transl releases the resource. Generally, a database server will not detect such a deadlock, because in general, to the database server trans1 and trans2 appear as independent transactions and it cannot assume that trans1 will not resume before trans2 completes. For example, the application could be multi-threaded, switching between trans1 and trans2 in successive fixed processing time intervals.
Traditional transaction processing mechanisms also present problems when two or more transactions are nested in a parent transaction, child transaction relationship. In past approaches, if the parent transaction aborts processing, the server causes all the child transactions to spontaneously abort. This is deemed necessary to ensure data consistency. However, in certain contexts it is important for a child transaction to be autonomous, so that if the child transaction completes without error it can commit, regardless of whether the parent transaction commits.
In some past approaches, recursive transaction support is provided. A recursive transaction is a separate, system-level transaction having no dependencies upon a parent transaction or child transaction upon commit. Such support is available in the Oracle.RTM. database server commercially available from Oracle Corporation, Redwood Shores, Calif. Recursive transactions are independent transactions that can be invoked only by Oracle database server. Recursive transactions do not support user savepoints and serializability. There is no concept of a recursive transaction scope. Users of recursive transactions, internal to the Oracle database servers, must explicitly start and end the recursive transactions, which could lead to programmatic errors.
Based on the foregoing, there is a clear need for a mechanism that facilitates the initiation and completion of autonomous transactions.
In particular, there is a need to provide a mechanism that enables an application program to have reusable application sub-components that perform specialized transactional operations. There is also a need to make such sub-components available to calling applications, without regard to the possible transaction state of the calling application, or the eventual disposition of the transaction.
Further, there is a need for a mechanism that enables an application program to create, manage, and terminate autonomous transactions, without requiring the application program or an application programmer to track each autonomous transaction by name.
Further, there is a need for a mechanism that enables a program or process to carry out one or more autonomous transactions, in which the autonomous transaction has no dependencies with respect to a transaction that calls the autonomous transaction.
There is a need for such a mechanism in which the mechanism can be used to construct reusable sub-components of application programs. There is also a need for such a mechanism in which an application can start a top-level transaction within another top-level transaction. There is a further need for such a mechanism in which the autonomous transaction can execute in the same manner as any other top-level transaction.
There is a further need for such a mechanism in which all changes made by an autonomous transaction are committed and are visible by the calling transaction and outside the calling transaction when the autonomous transaction commits.
There is also a need for an autonomous transaction mechanism that has no arbitrary limit on the nesting level of autonomous transactions. There is another need for an autonomous transaction mechanism in which all functions of regular transactions are available within an autonomous transaction.
Still another need is a transaction processing mechanism in which a calling transaction may call other transactions without having housekeeping code that deals with the possibility that the called transaction may fail to restore the context that existed immediately before the called transaction was called.